package com.zyl.add;

import java.util.concurrent.Semaphore;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author zhaoyl
 * @date 2024/5/16 11:25
 * @description 说明
 * Semaphore - 信号量
 * Semaphore（信号量）是用来控制同时访问特定资源的线程数量，它通过协调各个线程，以保证合理的使用公共资源。
 * 它用来控制访问资源的最大线程数量;例如下面抢占车位
 * 对比lock 接口, lock只允许同一时间一个线程访问,而 Semaphore 同一时间允许多个线程访问
 * 对比阻塞队列,应用场景类似,但也不一样; 阻塞队列 都是调节多线程协作,一块资源内容,允许多个线程同时访问, 也就是生产消费模式;
 * 而 Semaphore 的使用场景也类似是这种生产消费的模式,单不同的是, 它是控制一个资源的多个线程访问数量;
 */
public class SemaphoreDemo {
    private static int number = 3;
    public static void main(String[] args) {
        //同步计数器 初始化为 3
        AtomicInteger counter = new AtomicInteger(number);
     /* 由于acquire() 方法是一个阻塞方法,当可用凭证为0之后开始阻塞线程,直到已经获取到凭证的3个线程,
        其中有一个线程执行了 release(),此时可用凭证变为1 ,然后上一个被阻塞的线程它 调用了acquire(),
        才会恢复为就绪状态,然后获取凭证,开始执行;如此反复,知道最后一个线程开始执行,可用凭证开始从0 >>> 3 增加,
        直到全部结束,执行完成;*/
        Semaphore semaphore = new Semaphore(number);//限制最大并发3
        //开启7个线程争抢
        for (int i = 1;i<=7;i++){
            new Thread(()->{
                try {
                    //获取凭证，如果已经满则等待
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName()+"->抢到车位,剩余空闲"+counter.decrementAndGet());//decrementAndGet()-原子地将当前值减1并在减量后返回新值
                    int sleepMills = ThreadLocalRandom.current().nextInt(1000);
                  //  Thread.sleep(sleepMills);//毫秒
                    TimeUnit.MILLISECONDS.sleep(sleepMills);//2秒
                    System.out.println(Thread.currentThread().getName()+"->在休息"+sleepMills+"毫秒后离开车位");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    semaphore.release();//释放，当前信号量+1，然后该线程等待唤醒
                    System.out.println("当前空闲车位->"+counter.incrementAndGet());//incrementAndGet()以原子方式将当前值递增1并在递增后返回新值
                }
            },"线程"+String.valueOf(i)).start();
        }
    }
}
